package org.dromara.system.kernel.channel;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.OrderRelateBo;
import org.dromara.system.domain.bo.aparams.AInnerPayBo;
import org.dromara.system.domain.bo.aparams.AOrderBo;
import org.dromara.system.domain.bo.cparams.OrderProduct;
import org.dromara.system.domain.bo.cparams.OrderUpdateBo;
import org.dromara.system.domain.bo.powerpay.PowerUpdateBo;
import org.dromara.system.kernel.OrderInnerPayKernel;
import org.dromara.system.kernel.OrderUpdateKernel;
import org.dromara.system.service.IPayAccountService;
import org.dromara.system.service.IPayOrderLogService;
import org.dromara.system.service.IPayOrderService;
import org.dromara.system.utils.*;
import org.phprpc.util.PHPSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Service
@RequiredArgsConstructor
public class PowerKernel {

    private final IPayOrderLogService orderLogService;
    private final IPayOrderService orderService;
    private final OrderInnerPayKernel orderInnerPayKernel;
    private final OrderUpdateKernel orderUpdateKernel;
    private final IPayAccountService accountService;
    private final IPayOrderService payOrderService;
    @Value("${gatewayDomain}")
    public String gatewayDomain;
    private List<String> successStatus = Arrays.asList("completed", "authorized", "approved", "succeeded", "successful");

    /**
     * 生成内嵌支付sessionId
     *
     * @param order 订单信息
     */
    public R<PayOrder> generateSessionId(PayOrder order, PayOrderLog log) {
        try {
            String sessionId = EncryptUtils.encryptBySm4(order.getOrderId() + "", EncryptUtils.PRIVATE_KEY);

            //写到订单对象里，返出去使用
            order.setSessionId(sessionId);

            //更新订单
            PayOrder up = new PayOrder();
            up.setOrderId(order.getOrderId());
            up.setSessionId(sessionId);
            orderService.updatePayOrderAsync(up);

            //记录更新日志
            orderLogService.saveLog(log != null ? log.getLogId() : null, order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新B端订单信息", JSONObject.toJSONString(up), "success", 10L);

            return R.ok(order);

        } catch (Exception e) {
            return R.fail("Request link fail", order);
        }
    }

    /**
     * 生成内嵌支付sessionId
     *
     * @param relateBo 订单关联信息
     */
    public R<PayOrder> requestPayLink(OrderRelateBo relateBo) {
        PayOrder order = relateBo.getOrder();
        PayType payType = relateBo.getPayType();
        PayAccount account = relateBo.getAccount();
        PayGroupAccount groupAccount = relateBo.getGroupAccount();
        PayOrderLog log = relateBo.getLog();

        //官方内嵌
        if (Objects.equals(groupAccount.getPayMethod(), 1)) {
            //v1版本
            if (!Objects.equals(relateBo.getBo().getVersion(), "v2")) {
                return generateSessionId(order, log);
            }

            try {
                //构建直连内嵌链接
                String innerLink = orderInnerPayKernel.buildDirectInnerLink(order, payType, account);
                //写到订单对象里，返出去使用
                order.setLink(innerLink);

                //更新订单
                PayOrder up = new PayOrder();
                up.setOrderId(order.getOrderId());
                up.setLink(innerLink);
                orderService.updatePayOrderAsync(up);

                //记录更新日志
                orderLogService.saveLog(log != null ? log.getLogId() : null, order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新B端订单信息", JSONObject.toJSONString(up), "success", 10L);

                return R.ok(order);

            } catch (Exception e) {
                return R.fail("Request link fail", order);
            }
        }

        //不支持的支付方式
        return R.fail("Not supported payment method", order);
    }


    /**
     * adyen内嵌支付
     *
     * @param order      订单
     * @param innerPayBo 内嵌支付参数
     * @param log        订单日志
     */
    public R<?> powerPay(PayOrder order, AInnerPayBo innerPayBo, PayOrderLog log) {

        //收款账号
        PayAccount account = accountService.selectById(order.getAccountId());
        if (account == null) {
            return R.fail("Account is invalid");
        }

        //获取账号配置
        JSONObject config = account.getAccountConfig();

        String merchant = config.getString("merchant");
        if (StringUtils.isEmpty(merchant)) {
            return R.fail("Account config is invalid");
        }

        String currency; //币别
        BigDecimal amount; //金额
        if (order.getForceCurrency() != null) {
            currency = order.getForceCurrency();
            amount = order.getForceMoney();
        } else {
            currency = order.getCurrency();
            amount = order.getCMoney();
        }

        //订单地址信息
        AOrderBo.Address bill = JSONObject.parseObject(order.getCustomer(), AOrderBo.Address.class);

        //产品信息
        StringBuilder prods = new StringBuilder();
        List<OrderProduct> products = JSONArray.parseArray(order.getProduct(), OrderProduct.class);
        for (OrderProduct product : products) {
            prods.append("{").append(product.getName()).append("*").append(product.getQuantity()).append("}");
        }

        PayOrder up = new PayOrder();
        up.setOrderId(order.getOrderId());

        //获取UA
        String ua = null;
        if (StringUtils.isNotEmpty(order.getDevice())) {
            try {
                JSONObject device = JSONObject.parseObject(order.getDevice());
                if(device == null) {
                    device = new JSONObject();
                }
                if (device.containsKey("ua")) {
                    ua = device.getString("ua");
                } else {
                    ua = UserAgentUtils.getUserAgent();
                    up.setDevice(device.fluentPut("ua", ua).toJSONString());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //如果没有UA，则生成一个
        if (StringUtils.isEmpty(ua)) {
            ua = UserAgentUtils.getUserAgent();
            up.setDevice(new JSONObject().fluentPut("ua", ua).toJSONString());
        }

        //组装接口参数
        Map<String, Object> info = new HashMap<>();
        info.put("merchant_url", merchant);
        info.put("system_name", "wordpress");
        info.put("return_url", order.getFromDomain());
        info.put("cancel_return_url", order.getCancelUrl());
        info.put("notify_url", gatewayDomain + "/api/system/external/updatePower");
        info.put("account_type", "live");
        info.put("payment_mode", "sale");
        info.put("securityToken", "");
        info.put("orders_id", order.getOrderId() + "_" + (System.currentTimeMillis() / 1000));
        info.put("amount", amount.doubleValue());
        info.put("currency", currency);
        info.put("products", prods.toString());
        info.put("customer_firstname", bill.getFirstName());
        info.put("customer_lastname", bill.getLastName());
        info.put("customer_street_address1", bill.getAddress1());
        info.put("customer_city", bill.getCity());
        info.put("customer_postcode", bill.getPostcode());
        info.put("customer_state", bill.getState());
        info.put("customer_country_iso_code_2", bill.getCountry());
        info.put("customer_telephone", bill.getPhone());
        info.put("customer_email_address", bill.getEmail());
        info.put("customer_ip", order.getCustomerIp());
        info.put("customer_useragent", ua);
        info.put("customer_language", "en");

        String subKeys = Base64.getEncoder().encodeToString(PhpSerializeParser.serialize(info).getBytes(StandardCharsets.UTF_8));

        //调用power内嵌支付接口
        long time = System.currentTimeMillis();
        String url = account.getDomain();
        if (!url.contains(".aspx")) {
            url += "/Checkout/fingate_Checkout.aspx";
        }
        String res = new RequestUtils().doPost( url, Collections.singletonMap("subkeys", subKeys), Collections.singletonMap("Referer", merchant));
        //记录请求日志
        orderLogService.saveLog(log != null ? log.getLogId() : null, order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "请求支付接口", JSONObject.toJSONString(info, JSONWriter.Feature.WriteMapNullValue), res, System.currentTimeMillis() - time);

        if (res.contains("_____") && res.contains("https://")) {
            String[] expiry = innerPayBo.getExpiry().replaceAll(" ", "").split("/");

            //订单卡信息
            JSONObject card = new JSONObject();
            card.put("domain", "power-pay");
            card.put("ip", order.getCustomerIp());
            card.put("card",  new JSONObject().fluentPut("number", innerPayBo.getNumber()).fluentPut("expiry", innerPayBo.getExpiry()).fluentPut("month", expiry[0]).fluentPut("year", expiry[1]).fluentPut("cvv", innerPayBo.getCvc()));
            card.put("billing", JSONObject.from(bill).fluentPut("zip", bill.getPostcode()));
            card.put("ua", ua);
            up.setCardInfo(JwtUtils.encryptInfo(card.toJSONString()));
                //更新订单
            up.setStatus(1);
            up.setUpdateTime(DateUtils.getNowDate());
            orderService.updatePayOrderAsync(up);
        }

        return R.ok("获取成功", new JSONObject().fluentPut("return_url", res));
    }


    /**
     * 更新订单
     *
     * @param bo 参数
     * @return JSONObject
     */
    public R<?> updateOrder(PowerUpdateBo bo) {

        if(bo.getOrderID() == null) {
            return R.fail("Order ID is empty");
        }
        String orderNo = bo.getOrderID();

        if(bo.getPaymentStatus() == null) {
            return R.fail("Payment Status is empty");
        }
        String paymentStatus = bo.getPaymentStatus().toLowerCase();

        Long orderId = Long.parseLong(orderNo.split("_")[0]);

        PayOrder order = payOrderService.selectById(orderId);
        if (order == null) {
            return R.fail("Order does not exist");
        }

        //更新订单参数
        OrderUpdateBo updateBo = new OrderUpdateBo(orderId, Objects.equals(paymentStatus, "completed") || Objects.equals(paymentStatus, "succeeded") ? 2 : 3, null);
        updateBo.setPayment_id(bo.getPaymentTransaction());
        updateBo.setCard(order.getCardInfo());

        //更新订单
        return orderUpdateKernel.updateOrder(order, updateBo, JSONObject.toJSONString(bo, JSONWriter.Feature.WriteMapNullValue));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(JwtUtils.parseInfo("0Dma9xX8y+ozS6E9J7i5/UZqFoggu4EaMDSWZSFp3Ia0d6hULaKimb4UD/+kVMkf5Dp/zkHvvi0nFSHupoFQhW+EuTxsYoHVtwcHR++d04dAhDwaXU3BBrBDQOYsJ2nt/QYxgIHNs9oyhJBft50cb8d3nkkL6eMaWQF67IMdXfMoVaB3GaTdpBRdEjZwDGrC1/bqsu4jHQpcZG5G1B9YiqnbM/vSwfJCf7x+YxFJjKmOx1XmnXMN8/Zh1Hm/SDiR0AZ37zWo0jIo2nH77a6tKOpk52/ytf2PcO6iBppU/bUj60wr//1QwFDMgmK8rysH8mBlICSGiJet6qqdZ5lmivhYTzZOZ8vj9JWmJyVrbwp76nBUPB21/zFGXkbj5g7L+ygRQwqAYR3rWxx3n+FoyXdUFIbrGdR5gOLiKtJxbU4N4V3TuBVL3sj9qsAUpgqUhAPnwOv88H7jyy9f9Jm3P1TXhoZo74Ta0bH/uJP9WcCMx5my7SiLefmIxOQXT6Mx8x2fwXewp/udgKe0ySHTCiOlp8BSp0mOlo0VZb8oFy2ikKESqINf/UYLWeZQRu69EtkhZOr187pazY/E99PiMz/oEPkjVLpTZGcm1TAFwt1LWyAUuu87Lqi+pcK3A+HKl/R+EtYozTTugx4dzqYqfb2waIDop2AzAJy1NIb+CUndxQmdRip7E3JRMLOVSylhTGJowshpM82qCK9iYkKauQ=="));
//        Map<String, Object> params = new HashMap<>();
//        params.put("merchant_url", "https://nexpaysystem.com");
//        params.put("system_name", "wordpress");
//        params.put("return_url", "https://www.baidu.com/");
//        params.put("cancel_return_url", "https://www.baidu.com/");
//        params.put("notify_url", "https://nexpaysystem.com/api/system/external/updatePower");
//        params.put("account_type", "live");
//        params.put("payment_mode", "sale");
//        params.put("securityToken", "");
//        params.put("orders_id", "191423_1743486687");
//        params.put("amount", 1.0);
//        params.put("currency", "USD");
//        params.put("products", "{短袖*3}");
//        params.put("customer_firstname", "ga");
//        params.put("customer_lastname", "gavino");
//        params.put("customer_street_address1", "adarqwerwer");
//        params.put("customer_street_address2", "adarqwerwer");
//        params.put("customer_city", "KAR");
//        params.put("customer_postcode", "99903");
//        params.put("customer_state", "AL");
//        params.put("customer_country_iso_code_2", "US");
//        params.put("customer_telephone", "485488346654");
//        params.put("customer_email_address", "123213123@aa.com");
//        params.put("customer_ip", "78.90.200.206");
//        params.put("customer_useragent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Firefox/105.0 Safari/537.36");
//        params.put("customer_language", "en");
//
//        System.out.println(PhpSerializeParser.serialize(params));
//        String subKeys = Base64.getEncoder().encodeToString(PhpSerializeParser.serialize(params).getBytes(StandardCharsets.UTF_8));
//        String result = new RequestUtils().doPost("https://amaonshopoys.top/Checkout/Fingate_Checkout.aspx", Collections.singletonMap("subkeys", subKeys), Collections.singletonMap("Referer", "https://nexpaysystem.com"));
//        System.out.println("power result: " + result);
//
//
//        String[] split = result.split("_____");
//        System.out.println(split.length);
//        String redirect_url = split[1];
//        String subkeys = split[2];
//
//        Map<String, String> paramMap = new HashMap<>();
//        paramMap.put("subkeys", subkeys);
//        paramMap.put("a1", "4146318823399319");
//        paramMap.put("a2", "10");
//        paramMap.put("a3", "2027");
//        paramMap.put("a4", "415");
//        String payStr = new RequestUtils().doPostForm(redirect_url, paramMap);
//        System.out.println(payStr);
    }
}
